package com.eol.web.controller.pay;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipaySignature;
import com.eol.common.constants.BaseCommonConstants;
import com.eol.entity.dto.pay.PayInputDto;
import com.eol.entity.po.pay.ZPaymentTransactionLog;
import com.eol.service.pay.PayNotifyService;
import com.eol.service.pay.PayService;
import com.eol.service.pay.ZPaymentTransactionLogService;
import com.ijpay.alipay.AliPayApi;
import com.ijpay.alipay.AliPayApiConfig;
import com.ijpay.core.enums.SignType;
import com.ijpay.core.kit.HttpKit;
import com.ijpay.core.kit.WxPayKit;
import com.ijpay.wxpay.WxPayApiConfig;
import com.ijpay.wxpay.WxPayApiConfigKit;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * Created with IntelliJ IDEA.
 * User: liulinhui
 * Date: 2020/5/27
 * Time: 6:28 AM
 * Description: PayNotifyController
 */
@RestController
@RequestMapping
@Slf4j
public class PayNotifyController {

    @Resource
    private WxPayApiConfig wxPayApiConfig;
    @Resource
    private AliPayApiConfig aliPayApiConfig;
    @Resource
    private PayNotifyService payNotifyService;
    @Resource
    private ZPaymentTransactionLogService zPaymentTransactionLogService;

    /**
     * 阿里支付回调接口
     */
    @RequestMapping(value = PayService.ALI_PAY_NOTIFY_URL + "{orderId}/{channelType}/{type}")
    @Transactional
    public String aliCertNotifyUrl(HttpServletRequest request,
                                   @PathVariable("orderId") String orderId,
                                   @PathVariable("channelType") String channelType,
                                   @PathVariable("type") Integer type) {
        try {
            // 获取支付宝POST过来反馈信息
            Map<String, String> params = AliPayApi.toMap(request);
            log.info("收到支付宝支付回调:" + params.toString());
            for (Map.Entry<String, String> entry : params.entrySet()) {
                log.info(entry.getKey() + " = " + entry.getValue());
            }
            boolean verifyResult = AlipaySignature.rsaCheckV1(params, aliPayApiConfig.getAliPayPublicKey(), "UTF-8", "RSA2");
            if (verifyResult) {
                //判断订单状态
                if (payNotifyService.isOrderPayed(orderId, type)) {
                    return "success";
                }
                payNotifyService.paySuccess(orderId, type);
                //插入交易日志
                zPaymentTransactionLogService.insertSelective(ZPaymentTransactionLog.builder()
                        .id(orderId)
                        .createTime(new Date())
                        .notifyTime(new Date())
                        .channelType(channelType)
                        .channelName(BaseCommonConstants.CHANNEL_NAME_ALIPAY)
                        .payTime(new Date())
                        .trsId(params.get("trade_no"))
                        .notifyParams((JSONObject) JSONObject.toJSON(params))
                        .type(type)
                        .build());
                log.info("certNotifyUrl 验证成功succcess");
                return "success";
            } else {
                log.info("certNotifyUrl 验证失败");
                return "failure";
            }
        } catch (AlipayApiException e) {
            log.error("支付宝回调验证失败：");
            log.error(ExceptionUtils.getStackTrace(e));
            return "failure";
        }
    }

    @RequestMapping(value = PayService.WX_PAY_NOTIFY_URL + "{orderId}/{channelType}/{type}")
    @Transactional
    public String wxPayNotify(HttpServletRequest request,
                              @PathVariable("orderId") String orderId,
                              @PathVariable("channelType") String channelType,
                              @PathVariable("type") Integer type) {
        log.info("收到微信支付回调：" + orderId);
        String xmlMsg = HttpKit.readData(request);
        Map<String, String> params = WxPayKit.xmlToMap(xmlMsg);
        log.info("收到微信支付回调:" + xmlMsg);
        for (Map.Entry<String, String> entry : params.entrySet()) {
            log.info(entry.getKey() + " = " + entry.getValue());
        }
        WxPayApiConfigKit.setThreadLocalWxPayApiConfig(wxPayApiConfig);
        String returnCode = params.get("return_code");
        // 注意重复通知的情况，同一订单号可能收到多次通知，请注意一定先判断订单状态
        // 注意此处签名方式需与统一下单的签名类型一致
        log.info("校验支付");
        if (WxPayKit.verifyNotify(params, WxPayApiConfigKit.getWxPayApiConfig().getPartnerKey(), SignType.HMACSHA256)) {
            if (WxPayKit.codeIsOk(returnCode)) {
                log.info("校验支付成功" + returnCode);
                //判断订单状态
                if (payNotifyService.isOrderPayed(orderId, type)) {
                    log.info("订单已支付");
                    return "success";
                }
                payNotifyService.paySuccess(orderId, type);
                //插入交易日志
                zPaymentTransactionLogService.insertSelective(ZPaymentTransactionLog.builder()
                        .id(orderId)
                        .createTime(new Date())
                        .notifyTime(new Date())
                        .channelType(channelType)
                        .channelName(BaseCommonConstants.CHANNEL_NAME_WX)
                        .payTime(new Date())
                        .trsId(params.get("transaction_id"))
                        .notifyParams((JSONObject) JSONObject.toJSON(params))
                        .type(type)
                        .build());
                Map<String, String> xml = new HashMap<>(2);
                xml.put("return_code", "SUCCESS");
                xml.put("return_msg", "OK");
                return WxPayKit.toXml(xml);
            }
        }
        return null;
    }
}
